<template>
  <div ref="container" class="scroll-y-container" :style="{ height: height }">
    <div
      ref="content"
      :class="[
        'scroll-y-content',
        { centered: !isOverflow && align === 'center' },
        { top: !isOverflow && align === 'top' },
        { bottom: !isOverflow && align === 'bottom' },
      ]"
      :style="contentStyle"
      @mouseenter="hoverPause && pauseScroll()"
      @mouseleave="hoverPause && resumeScroll()"
    >
      <div ref="slotWrap" class="slot-wrap">
        <slot />
      </div>
      <div v-if="isOverflow" class="slot-wrap">
        <slot />
      </div>
    </div>
  </div>
</template>

<script>
import { debounce } from "lodash";

export default {
  name: "ScrollY",
  props: {
    speed: {
      type: Number,
      default: 30,
    },
    height: {
      type: [String, Number],
      default: "100%",
    },
    align: {
      type: String,
      default: "top",
      validator: (value) => ["top", "center", "bottom"].includes(value),
    },
    enabled: {
      type: Boolean,
      default: true,
    },
    // 添加新的 prop 控制鼠标划入是否暂停
    hoverPause: {
      type: Boolean,
      default: false, // 默认为 true，保持原有行为
    },
  },
  data() {
    return {
      isOverflow: false,
      animationFrame: null,
      scrollTop: 0,
      containerHeight: 0,
      contentHeight: 0,
      running: true,
      observer: null,
      resizeObserver: null,
      isVisible: true,
      isMounted: false,
      lastTimestamp: 0,
      currentScrollRatio: 0,
    };
  },
  computed: {
    realSpeed() {
      const baseScreen = 1080;
      const currentScreen = window.innerHeight || baseScreen;
      return (this.speed * currentScreen) / baseScreen;
    },
    contentStyle() {
      const baseStyle = {
        height: this.isOverflow ? this.contentHeight * 2 + "px" : "auto",
        display: "flex",
        flexDirection: "column",
        transition: "none",
        lineHeight: "inherit",
        fontSize: "inherit",
        letterSpacing: "normal",
        wordSpacing: "normal",
        willChange: "transform",
        backfaceVisibility: "hidden",
        perspective: 1000,
        transformStyle: "preserve-3d",
        transform: "translateZ(0)",
      };

      return {
        ...baseStyle,
        transform: this.isOverflow
          ? `translate3d(0, -${this.scrollTop}px, 0) translateZ(0)`
          : "translateZ(0)",
      };
    },
  },
  watch: {
    enabled: {
      handler(newVal) {
        if (newVal) {
          this.checkOverflow();
        } else {
          this.stopScroll();
        }
      },
      immediate: true,
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.isMounted = true;
      this.initObservers();
      this.checkOverflow();
    });
  },
  beforeDestroy() {
    this.stopScroll();
    this.destroyObservers();
  },
  methods: {
    initObservers() {
      if (!this.$refs.slotWrap) return;
      const debouncedCheckOverflow = debounce(this.checkOverflow, 100);

      this.observer = new MutationObserver((mutations) => {
        const hasContentChange = mutations.some((mutation) => {
          return (
            mutation.type === "childList" ||
            mutation.type === "characterData" ||
            (mutation.type === "attributes" &&
              mutation.attributeName !== "style" &&
              mutation.attributeName !== "class")
          );
        });

        if (hasContentChange) {
          if (this.contentHeight > 0) {
            this.currentScrollRatio = this.scrollTop / this.contentHeight;
          }
          debouncedCheckOverflow();
        }
      });

      this.observer.observe(this.$refs.slotWrap, {
        childList: true,
        subtree: true,
        characterData: true,
        attributes: true,
      });

      this.resizeObserver = new ResizeObserver(debouncedCheckOverflow);
      this.resizeObserver.observe(this.$refs.container);
      this.resizeObserver.observe(this.$refs.slotWrap);

      window.addEventListener("resize", debouncedCheckOverflow);
    },
    destroyObservers() {
      if (this.observer) {
        this.observer.disconnect();
        this.observer = null;
      }
      if (this.resizeObserver) {
        this.resizeObserver.disconnect();
        this.resizeObserver = null;
      }
      window.removeEventListener("resize", this.debouncedCheckOverflow);
    },
    checkOverflow() {
      if (!this.isMounted || !this.enabled || !this.isVisible) return;
      if (!this.$refs.container || !this.$refs.slotWrap) return;

      this.$nextTick(() => {
        try {
          const containerHeight = this.$refs.container.offsetHeight;
          const contentHeight = this.$refs.slotWrap.scrollHeight;
          const wasOverflow = this.isOverflow;
          const oldContentHeight = this.contentHeight;

          this.isOverflow = contentHeight > containerHeight;

          if (this.isOverflow) {
            this.containerHeight = containerHeight;
            this.contentHeight = contentHeight;

            if (wasOverflow && oldContentHeight !== contentHeight) {
              this.scrollTop = Math.floor(
                this.currentScrollRatio * contentHeight
              );
            } else {
              this.scrollTop = 0;
            }

            this.$nextTick(() => {
              this.startScroll();
            });
          } else {
            this.stopScroll();
            this.scrollTop = 0;
          }

          console.log("Overflow check:", {
            isOverflow: this.isOverflow,
            containerHeight,
            contentHeight,
            scrollTop: this.scrollTop,
            currentScrollRatio: this.currentScrollRatio,
          });
        } catch (error) {
          console.warn("ScrollY checkOverflow error:", error);
        }
      });
    },
    startScroll() {
      if (!this.isOverflow) return;

      this.running = true;
      this.lastTimestamp = 0;

      const step = (timestamp) => {
        if (!this.running || !this.isOverflow) {
          return;
        }

        if (!this.lastTimestamp) {
          this.lastTimestamp = timestamp;
          this.animationFrame = requestAnimationFrame(step);
          return;
        }

        const delta = timestamp - this.lastTimestamp;
        this.lastTimestamp = timestamp;

        const scrollAmount = (this.realSpeed * delta) / 500;
        this.scrollTop += scrollAmount;

        this.currentScrollRatio = this.scrollTop / this.contentHeight;

        if (this.scrollTop >= this.contentHeight) {
          this.scrollTop = 0;
          this.currentScrollRatio = 0;
          this.lastTimestamp = timestamp;
        }

        this.animationFrame = requestAnimationFrame(step);
      };

      this.animationFrame = requestAnimationFrame(step);
    },
    stopScroll() {
      this.running = false;
      if (this.animationFrame) {
        cancelAnimationFrame(this.animationFrame);
        this.animationFrame = null;
      }
    },
    pauseScroll() {
      if (!this.hoverPause) return;
      if (!this.isOverflow || !this.enabled || !this.isVisible) return;
      this.running = false;
    },
    resumeScroll() {
      if (!this.hoverPause) return;
      if (!this.running && this.isOverflow && this.enabled && this.isVisible) {
        this.running = true;
        this.animationFrame = requestAnimationFrame((timestamp) => {
          this.lastTimestamp = timestamp;
          const step = (currentTimestamp) => {
            if (!this.running || !this.isOverflow) {
              return;
            }

            const delta = currentTimestamp - this.lastTimestamp;
            this.lastTimestamp = currentTimestamp;

            const scrollAmount = (this.realSpeed * delta) / 500;
            this.scrollTop += scrollAmount;

            this.currentScrollRatio = this.scrollTop / this.contentHeight;

            if (this.scrollTop >= this.contentHeight) {
              this.scrollTop = 0;
              this.currentScrollRatio = 0;
              this.lastTimestamp = currentTimestamp;
            }

            this.animationFrame = requestAnimationFrame(step);
          };
          this.animationFrame = requestAnimationFrame(step);
        });
      }
    },
    show() {
      this.isVisible = true;
      this.checkOverflow();
    },
    hide() {
      this.isVisible = false;
      this.stopScroll();
    },
  },
};
</script>

<style scoped>
.scroll-y-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow-y: hidden;
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.scroll-y-content {
  width: 100%;
  height: 100%;
  will-change: transform;
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  contain: content;
  content-visibility: auto;
  transition: transform 0.3s ease-out;
}

.slot-wrap {
  display: flex;
  flex-direction: column;
  
  width: 100%;
  margin: 0;
  padding: 0;
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.scroll-y-content.top,
.scroll-y-content.bottom,
.scroll-y-content.centered {
  display: flex;
  flex-direction: column;
  align-items: center;
  transform: none !important;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.scroll-y-content.top {
  justify-content: flex-start;
}

.scroll-y-content.bottom {
  justify-content: flex-end;
}

.scroll-y-content.centered {
  justify-content: center;
}
</style>
